/*-------------------------------------------------------------------------
 *
 * multirangetypes.c
 *	  I/O 函数、运算符和多范围类型的支持函数。
 *
 * 多范围值的存储（序列化）格式为：
 *
 *	12 字节：MultirangeType 结构，包括 varlena 头部、多范围
 *			  类型的 OID 和多范围中的范围数量。
 *	4 * (rangesCount - 1) 字节：指向多范围中每个范围的 32 位项，
 *								 从第二个范围开始。
 *	1 * rangesCount 字节：多范围中每个范围的 8 位标志
 * 其余的多范围是由多范围项指向的范围边界值。
 *
 *	大多数项包含对应范围边界值的长度。
 *	因此，项通常是低数字。这使得多范围具有压缩友好性。
 *	每个 MULTIRANGE_ITEM_OFFSET_STRIDE 项包含对应范围边界值的偏移。
 *	这允许对特定范围索引进行快速查找。偏移是从边界类型对齐的
 *	标志末尾开始计数。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/utils/adt/multirangetypes.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/tupmacs.h"
#include "common/hashfn.h"
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "port/pg_bitutils.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rangetypes.h"
#include "utils/multirangetypes.h"
#include "utils/array.h"
#include "utils/memutils.h"

/* 一个范围 I/O 函数的 fn_extra 缓存条目 */
typedef struct MultirangeIOData
{
	TypeCacheEntry *typcache;	/* multirange 类型的 typcache 条目 */
	FmgrInfo	typioproc;		/* range 类型的 I/O 过程 */
	Oid			typioparam;		/* range 类型的 I/O 参数 */
} MultirangeIOData;

typedef enum
{
	MULTIRANGE_BEFORE_RANGE,
	MULTIRANGE_IN_RANGE,
	MULTIRANGE_IN_RANGE_ESCAPED,
	MULTIRANGE_IN_RANGE_QUOTED,
	MULTIRANGE_IN_RANGE_QUOTED_ESCAPED,
	MULTIRANGE_AFTER_RANGE,
	MULTIRANGE_FINISHED,
} MultirangeParseState;

/*
 * 访问 multirange 的 past MultirangeType 部分的宏：项、标志
 * 和边界。
 */
#define MultirangeGetItemsPtr(mr) ((uint32 *) ((Pointer) (mr) + \
	sizeof(MultirangeType)))
#define MultirangeGetFlagsPtr(mr) ((uint8 *) ((Pointer) (mr) + \
	sizeof(MultirangeType) + ((mr)->rangeCount - 1) * sizeof(uint32)))
#define MultirangeGetBoundariesPtr(mr, align) ((Pointer) (mr) + \
	att_align_nominal(sizeof(MultirangeType) + \
		((mr)->rangeCount - 1) * sizeof(uint32) + \
		(mr)->rangeCount * sizeof(uint8), (align)))

#define MULTIRANGE_ITEM_OFF_BIT 0x80000000
#define MULTIRANGE_ITEM_GET_OFFLEN(item) ((item) & 0x7FFFFFFF)
#define MULTIRANGE_ITEM_HAS_OFF(item) ((item) & MULTIRANGE_ITEM_OFF_BIT)
#define MULTIRANGE_ITEM_OFFSET_STRIDE 4

typedef int (*multirange_bsearch_comparison) (TypeCacheEntry *typcache,
											  RangeBound *lower,
											  RangeBound *upper,
											  void *key,
											  bool *match);

static MultirangeIOData *get_multirange_io_data(FunctionCallInfo fcinfo,
												Oid fc_mltrngtypid,
												IOFuncSelector fc_func);
static int32 fc_multirange_canonicalize(TypeCacheEntry *fc_rangetyp,
									 int32 fc_input_range_count,
									 RangeType **fc_ranges);

/*
 * ----------------------------------------------------------
 * I/O 函数
 * ----------------------------------------------------------
 */

/*
 * 将字符串转换为 multirange。
 *
 * 我们期望花括号界定列表，零个或多个范围
 * 用逗号分隔。 我们接受任何地方的空白：在我们的
 * 括号之前/之后以及逗号周围。 范围可以是空字面量或一些
 * 在括号/括号内的内容。 大部分情况下，我们将单独范围内容的解析委托给 range_in，但我们必须检测引号和
 * 反斜杠转义，这可能发生在范围边界。 反斜杠可以
 * 转义引号字符串内部或外部的内容，且引号字符串
 * 可以用反斜杠或双引号转义引号。
 */
Datum multirange_in(PG_FUNCTION_ARGS)
{
	char	   *fc_input_str = PG_GETARG_CSTRING(0);
	Oid			fc_mltrngtypoid = PG_GETARG_OID(1);
	Oid			fc_typmod = PG_GETARG_INT32(2);
	TypeCacheEntry *fc_rangetyp;
	int32		fc_ranges_seen = 0;
	int32		fc_range_count = 0;
	int32		fc_range_capacity = 8;
	RangeType  *fc_range;
	RangeType **fc_ranges = palloc(fc_range_capacity * sizeof(RangeType *));
	MultirangeIOData *fc_cache;
	MultirangeType *fc_ret;
	MultirangeParseState fc_parse_state;
	const char *fc_ptr = fc_input_str;
	const char *fc_range_str_begin = NULL;
	int32		fc_range_str_len;
	char	   *fc_range_str;

	fc_cache = get_multirange_io_data(fcinfo, fc_mltrngtypoid, IOFunc_input);
	fc_rangetyp = fc_cache->typcache->rngtype;

	/* 消耗空白 */
	while (*fc_ptr != '\0' && isspace((unsigned char) *fc_ptr))
		fc_ptr++;

	if (*fc_ptr == '{')
		fc_ptr++;
	else
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("malformed multirange literal: \"%s\"",
						fc_input_str),
				 errdetail("Missing left brace.")));

	/* 消耗范围 */
	fc_parse_state = MULTIRANGE_BEFORE_RANGE;
	for (; fc_parse_state != MULTIRANGE_FINISHED; fc_ptr++)
	{
		char		fc_ch = *fc_ptr;

		if (fc_ch == '\0')
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
					 errmsg("malformed multirange literal: \"%s\"",
							fc_input_str),
					 errdetail("Unexpected end of input.")));

		/* 跳过空白 */
		if (isspace((unsigned char) fc_ch))
			continue;

		switch (fc_parse_state)
		{
			case MULTIRANGE_BEFORE_RANGE:
				if (fc_ch == '[' || fc_ch == '(')
				{
					fc_range_str_begin = fc_ptr;
					fc_parse_state = MULTIRANGE_IN_RANGE;
				}
				else if (fc_ch == '}' && fc_ranges_seen == 0)
					fc_parse_state = MULTIRANGE_FINISHED;
				else if (pg_strncasecmp(fc_ptr, RANGE_EMPTY_LITERAL,
										strlen(RANGE_EMPTY_LITERAL)) == 0)
				{
					fc_ranges_seen++;
					/* 对于空范围没有任何事情可做 */
					fc_ptr += strlen(RANGE_EMPTY_LITERAL) - 1;
					fc_parse_state = MULTIRANGE_AFTER_RANGE;
				}
				else
					ereport(ERROR,
							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
							 errmsg("malformed multirange literal: \"%s\"",
									fc_input_str),
							 errdetail("Expected range start.")));
				break;
			case MULTIRANGE_IN_RANGE:
				if (fc_ch == ']' || fc_ch == ')')
				{
					fc_range_str_len = fc_ptr - fc_range_str_begin + 1;
					fc_range_str = pnstrdup(fc_range_str_begin, fc_range_str_len);
					if (fc_range_capacity == fc_range_count)
					{
						fc_range_capacity *= 2;
						fc_ranges = (RangeType **)
							repalloc(fc_ranges, fc_range_capacity * sizeof(RangeType *));
					}
					fc_ranges_seen++;
					fc_range = DatumGetRangeTypeP(InputFunctionCall(&fc_cache->typioproc,
																 fc_range_str,
																 fc_cache->typioparam,
																 fc_typmod));
					if (!RangeIsEmpty(fc_range))
						fc_ranges[fc_range_count++] = fc_range;
					fc_parse_state = MULTIRANGE_AFTER_RANGE;
				}
				else
				{
					if (fc_ch == '"')
						fc_parse_state = MULTIRANGE_IN_RANGE_QUOTED;
					else if (fc_ch == '\\')
						fc_parse_state = MULTIRANGE_IN_RANGE_ESCAPED;

					/*
					 * 一旦我们找到范围值的结束，
					 * 我们将把这个字符包含到 range_str 中。
					 */
				}
				break;
			case MULTIRANGE_IN_RANGE_ESCAPED:

				/*
				 * 一旦我们找到范围值的结束，
				 * 我们将把这个字符包含到 range_str 中。
				 */
				fc_parse_state = MULTIRANGE_IN_RANGE;
				break;
			case MULTIRANGE_IN_RANGE_QUOTED:
				if (fc_ch == '"')
					if (*(fc_ptr + 1) == '"')
					{
						/* 两个引号表示转义引号 */
						fc_ptr++;
					}
					else
						fc_parse_state = MULTIRANGE_IN_RANGE;
				else if (fc_ch == '\\')
					fc_parse_state = MULTIRANGE_IN_RANGE_QUOTED_ESCAPED;

				/*
				 * 一旦我们找到范围值的结束，
				 * 我们将把这个字符包含到 range_str 中。
				 */
				break;
			case MULTIRANGE_AFTER_RANGE:
				if (fc_ch == ',')
					fc_parse_state = MULTIRANGE_BEFORE_RANGE;
				else if (fc_ch == '}')
					fc_parse_state = MULTIRANGE_FINISHED;
				else
					ereport(ERROR,
							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
							 errmsg("malformed multirange literal: \"%s\"",
									fc_input_str),
							 errdetail("Expected comma or end of multirange.")));
				break;
			case MULTIRANGE_IN_RANGE_QUOTED_ESCAPED:

				/*
				 * 一旦我们找到范围值的结束，
				 * 我们将把这个字符包含到 range_str 中。
				 */
				fc_parse_state = MULTIRANGE_IN_RANGE_QUOTED;
				break;
			default:
				elog(ERROR, "unknown parse state: %d", fc_parse_state);
		}
	}

	/* 消耗空白 */
	while (*fc_ptr != '\0' && isspace((unsigned char) *fc_ptr))
		fc_ptr++;

	if (*fc_ptr != '\0')
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("malformed multirange literal: \"%s\"",
						fc_input_str),
				 errdetail("Junk after closing right brace.")));

	fc_ret = make_multirange(fc_mltrngtypoid, fc_rangetyp, fc_range_count, fc_ranges);
	PG_RETURN_MULTIRANGE_P(fc_ret);
}

Datum multirange_out(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_multirange = PG_GETARG_MULTIRANGE_P(0);
	Oid			fc_mltrngtypoid = MultirangeTypeGetOid(fc_multirange);
	MultirangeIOData *fc_cache;
	StringInfoData fc_buf;
	RangeType  *fc_range;
	char	   *fc_rangeStr;
	int32		fc_range_count;
	int32		fc_i;
	RangeType **fc_ranges;

	fc_cache = get_multirange_io_data(fcinfo, fc_mltrngtypoid, IOFunc_output);

	initStringInfo(&fc_buf);

	appendStringInfoChar(&fc_buf, '{');

	multirange_deserialize(fc_cache->typcache->rngtype, fc_multirange, &fc_range_count, &fc_ranges);
	for (fc_i = 0; fc_i < fc_range_count; fc_i++)
	{
		if (fc_i > 0)
			appendStringInfoChar(&fc_buf, ',');
		fc_range = fc_ranges[fc_i];
		fc_rangeStr = OutputFunctionCall(&fc_cache->typioproc, RangeTypePGetDatum(fc_range));
		appendStringInfoString(&fc_buf, fc_rangeStr);
	}

	appendStringInfoChar(&fc_buf, '}');

	PG_RETURN_CSTRING(fc_buf.data);
}

/*
 * 二进制表示：首先是一个 int32 大小的范围计数，后跟
 * 其本地二进制表示的范围。
 */
Datum multirange_recv(PG_FUNCTION_ARGS)
{
	StringInfo	fc_buf = (StringInfo) PG_GETARG_POINTER(0);
	Oid			fc_mltrngtypoid = PG_GETARG_OID(1);
	int32		fc_typmod = PG_GETARG_INT32(2);
	MultirangeIOData *fc_cache;
	uint32		fc_range_count;
	RangeType **fc_ranges;
	MultirangeType *fc_ret;
	StringInfoData fc_tmpbuf;

	fc_cache = get_multirange_io_data(fcinfo, fc_mltrngtypoid, IOFunc_receive);

	fc_range_count = pq_getmsgint(fc_buf, 4);
	fc_ranges = palloc(fc_range_count * sizeof(RangeType *));

	initStringInfo(&fc_tmpbuf);
	for (int fc_i = 0; fc_i < fc_range_count; fc_i++)
	{
		uint32		fc_range_len = pq_getmsgint(fc_buf, 4);
		const char *fc_range_data = pq_getmsgbytes(fc_buf, fc_range_len);

		resetStringInfo(&fc_tmpbuf);
		appendBinaryStringInfo(&fc_tmpbuf, fc_range_data, fc_range_len);

		fc_ranges[fc_i] = DatumGetRangeTypeP(ReceiveFunctionCall(&fc_cache->typioproc,
														   &fc_tmpbuf,
														   fc_cache->typioparam,
														   fc_typmod));
	}
	pfree(fc_tmpbuf.data);

	pq_getmsgend(fc_buf);

	fc_ret = make_multirange(fc_mltrngtypoid, fc_cache->typcache->rngtype,
						  fc_range_count, fc_ranges);
	PG_RETURN_MULTIRANGE_P(fc_ret);
}

Datum multirange_send(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_multirange = PG_GETARG_MULTIRANGE_P(0);
	Oid			fc_mltrngtypoid = MultirangeTypeGetOid(fc_multirange);
	StringInfo	fc_buf = makeStringInfo();
	RangeType **fc_ranges;
	int32		fc_range_count;
	MultirangeIOData *fc_cache;

	fc_cache = get_multirange_io_data(fcinfo, fc_mltrngtypoid, IOFunc_send);

	/* 构造输出 */
	pq_begintypsend(fc_buf);

	pq_sendint32(fc_buf, fc_multirange->rangeCount);

	multirange_deserialize(fc_cache->typcache->rngtype, fc_multirange, &fc_range_count, &fc_ranges);
	for (int fc_i = 0; fc_i < fc_range_count; fc_i++)
	{
		Datum		fc_range;

		fc_range = RangeTypePGetDatum(fc_ranges[fc_i]);
		fc_range = PointerGetDatum(SendFunctionCall(&fc_cache->typioproc, fc_range));

		pq_sendint32(fc_buf, VARSIZE(fc_range) - VARHDRSZ);
		pq_sendbytes(fc_buf, VARDATA(fc_range), VARSIZE(fc_range) - VARHDRSZ);
	}

	PG_RETURN_BYTEA_P(pq_endtypsend(fc_buf));
}

/*
 * get_multirange_io_data：获取多范围类型 I/O 所需的缓存信息
 *
 * 多范围 I/O 函数需要比其他多范围函数更多的缓存信息，
 * 因此它们在 fn_extra 中存储一个 MultirangeIOData 结构，
 * 而不仅仅是指向类型缓存条目的指针。
 */
static MultirangeIOData *
get_multirange_io_data(FunctionCallInfo fcinfo, Oid fc_mltrngtypid, IOFuncSelector fc_func)
{
	MultirangeIOData *fc_cache = (MultirangeIOData *) fcinfo->flinfo->fn_extra;

	if (fc_cache == NULL || fc_cache->typcache->type_id != fc_mltrngtypid)
	{
		Oid			fc_typiofunc;
		int16		fc_typlen;
		bool		fc_typbyval;
		char		fc_typalign;
		char		fc_typdelim;

		fc_cache = (MultirangeIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
														sizeof(MultirangeIOData));
		fc_cache->typcache = lookup_type_cache(fc_mltrngtypid, TYPECACHE_MULTIRANGE_INFO);
		if (fc_cache->typcache->rngtype == NULL)
			elog(ERROR, "type %u is not a multirange type", fc_mltrngtypid);

		/* get_type_io_data 做的比我们需要的更多，但很方便 */
		get_type_io_data(fc_cache->typcache->rngtype->type_id,
						 fc_func,
						 &fc_typlen,
						 &fc_typbyval,
						 &fc_typalign,
						 &fc_typdelim,
						 &fc_cache->typioparam,
						 &fc_typiofunc);

		if (!OidIsValid(fc_typiofunc))
		{
			/* 这只能发生在接收或发送情况下 */
			if (fc_func == IOFunc_receive)
				ereport(ERROR,
						(errcode(ERRCODE_UNDEFINED_FUNCTION),
						 errmsg("no binary input function available for type %s",
								format_type_be(fc_cache->typcache->rngtype->type_id))));
			else
				ereport(ERROR,
						(errcode(ERRCODE_UNDEFINED_FUNCTION),
						 errmsg("no binary output function available for type %s",
								format_type_be(fc_cache->typcache->rngtype->type_id))));
		}
		fmgr_info_cxt(fc_typiofunc, &fc_cache->typioproc,
					  fcinfo->flinfo->fn_mcxt);

		fcinfo->flinfo->fn_extra = (void *) fc_cache;
	}

	return fc_cache;
}

/*
 * 将任意范围的列表转换为已排序和合并的列表。
 * 修改 `ranges` 的内容。
 *
 * 返回实际使用的槽数，这可能少于 input_range_count，但绝不会更多。
 *
 * 我们假设没有输入范围为 null，但空范围是可以的。
 */
static int32 fc_multirange_canonicalize(TypeCacheEntry *fc_rangetyp, int32 fc_input_range_count,
						RangeType **fc_ranges)
{
	RangeType  *fc_lastRange = NULL;
	RangeType  *fc_currentRange;
	int32		fc_i;
	int32		fc_output_range_count = 0;

	/* 排序范围，以便我们可以找到重叠/相邻的范围。 */
	qsort_arg(fc_ranges, fc_input_range_count, sizeof(RangeType *), range_compare,
			  fc_rangetyp);

	/* 现在合并可能的地方： */
	for (fc_i = 0; fc_i < fc_input_range_count; fc_i++)
	{
		fc_currentRange = fc_ranges[fc_i];
		if (RangeIsEmpty(fc_currentRange))
			continue;

		if (fc_lastRange == NULL)
		{
			fc_ranges[fc_output_range_count++] = fc_lastRange = fc_currentRange;
			continue;
		}

		/*
		 * range_adjacent_internal 如果 A 与 B 相接或 B 与 A 相接，则返回真，
		 * 这并不是我们想要的，但我们依赖上面的排序
		 * 来排除 B 与 A 相接永远发生的情况。
		 */
		if (range_adjacent_internal(fc_rangetyp, fc_lastRange, fc_currentRange))
		{
			/* 两个范围接触（没有重叠），所以合并它们： */
			fc_ranges[fc_output_range_count - 1] = fc_lastRange =
				range_union_internal(fc_rangetyp, fc_lastRange, fc_currentRange, false);
		}
		else if (range_before_internal(fc_rangetyp, fc_lastRange, fc_currentRange))
		{
			/* 有一个间隙，所以创建一个新条目： */
			fc_lastRange = fc_ranges[fc_output_range_count] = fc_currentRange;
			fc_output_range_count++;
		}
		else
		{
			/* 它们必须重叠，所以合并它们： */
			fc_ranges[fc_output_range_count - 1] = fc_lastRange =
				range_union_internal(fc_rangetyp, fc_lastRange, fc_currentRange, true);
		}
	}

	return fc_output_range_count;
}

/*
 *----------------------------------------------------------
 * 支持函数
 *
 *	 这些函数不在 pg_proc 中，但对于
 *	 在 C 中定义新的通用多范围函数非常有用。
 *----------------------------------------------------------
 */

/*
 * multirange_get_typcache：获取有关多范围类型的缓存信息
 *
 * 这用于多范围相关函数，这些函数遵循将 fn_extra 字段
 * 作为多范围类型的类型缓存条目的指针的约定。
 * 需要缓存比这更多信息的函数必须自己解决。
 */
TypeCacheEntry * multirange_get_typcache(FunctionCallInfo fcinfo, Oid fc_mltrngtypid)
{
	TypeCacheEntry *fc_typcache = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;

	if (fc_typcache == NULL ||
		fc_typcache->type_id != fc_mltrngtypid)
	{
		fc_typcache = lookup_type_cache(fc_mltrngtypid, TYPECACHE_MULTIRANGE_INFO);
		if (fc_typcache->rngtype == NULL)
			elog(ERROR, "type %u is not a multirange type", fc_mltrngtypid);
		fcinfo->flinfo->fn_extra = (void *) fc_typcache;
	}

	return fc_typcache;
}


/*
 * 估算序列化多范围占用的大小。
 */
static Size fc_multirange_size_estimate(TypeCacheEntry *fc_rangetyp, int32 fc_range_count,
						 RangeType **fc_ranges)
{
	char		fc_elemalign = fc_rangetyp->rngelemtype->typalign;
	Size		fc_size;
	int32		fc_i;

	/*
	 * 计算 MultirangeType 结构、项目和标志所占的空间。
	 */
	fc_size = att_align_nominal(sizeof(MultirangeType) +
							 Max(fc_range_count - 1, 0) * sizeof(uint32) +
							 fc_range_count * sizeof(uint8), fc_elemalign);

	/* 计算范围边界所占的空间 */
	for (fc_i = 0; fc_i < fc_range_count; fc_i++)
		fc_size += att_align_nominal(VARSIZE(fc_ranges[fc_i]) -
								  sizeof(RangeType) -
								  sizeof(char), fc_elemalign);

	return fc_size;
}

/*
 * 将多范围数据写入预分配的空间。
 */
static void fc_write_multirange_data(MultirangeType *fc_multirange, TypeCacheEntry *fc_rangetyp,
					  int32 fc_range_count, RangeType **fc_ranges)
{
	uint32	   *fc_items;
	uint32		fc_prev_offset = 0;
	uint8	   *fc_flags;
	int32		fc_i;
	Pointer		fc_begin,
				fc_ptr;
	char		fc_elemalign = fc_rangetyp->rngelemtype->typalign;

	fc_items = MultirangeGetItemsPtr(fc_multirange);
	fc_flags = MultirangeGetFlagsPtr(fc_multirange);
	fc_ptr = fc_begin = MultirangeGetBoundariesPtr(fc_multirange, fc_elemalign);
	for (fc_i = 0; fc_i < fc_range_count; fc_i++)
	{
		uint32		fc_len;

		if (fc_i > 0)
		{
			/*
			 * 每个范围，除了第一个，都有一个项目。每个
			 * MULTIRANGE_ITEM_OFFSET_STRIDE 项目包含一个偏移量，其他
			 * 项目包含长度。
			 */
			fc_items[fc_i - 1] = fc_ptr - fc_begin;
			if ((fc_i % MULTIRANGE_ITEM_OFFSET_STRIDE) != 0)
				fc_items[fc_i - 1] -= fc_prev_offset;
			else
				fc_items[fc_i - 1] |= MULTIRANGE_ITEM_OFF_BIT;
			fc_prev_offset = fc_ptr - fc_begin;
		}
		fc_flags[fc_i] = *((Pointer) fc_ranges[fc_i] + VARSIZE(fc_ranges[fc_i]) - sizeof(char));
		fc_len = VARSIZE(fc_ranges[fc_i]) - sizeof(RangeType) - sizeof(char);
		memcpy(fc_ptr, (Pointer) (fc_ranges[fc_i] + 1), fc_len);
		fc_ptr += att_align_nominal(fc_len, fc_elemalign);
	}
}


/*
 * 这会将多范围从一个非空范围的列表序列化。
 * 它还会对范围进行排序，并合并任何接触的范围。
 * 范围应该已经被去吐槽，并且不应该有 NULL。
 * 大多数调用者应该使用这个。
 *
 * 请注意，我们可能会更改 `ranges` 参数（指针，但不
 * 包含任何已经存在的 RangeType 内容）。
 */
MultirangeType * make_multirange(Oid fc_mltrngtypoid, TypeCacheEntry *fc_rangetyp, int32 fc_range_count,
				RangeType **fc_ranges)
{
	MultirangeType *fc_multirange;
	Size		fc_size;

	/* 排序和合并输入范围。 */
	fc_range_count = fc_multirange_canonicalize(fc_rangetyp, fc_range_count, fc_ranges);

	/* 注意：这里需要零填充，就像在堆元组中一样 */
	fc_size = fc_multirange_size_estimate(fc_rangetyp, fc_range_count, fc_ranges);
	fc_multirange = palloc0(fc_size);
	SET_VARSIZE(fc_multirange, fc_size);

	/* 现在填充数据项 */
	fc_multirange->multirangetypid = fc_mltrngtypoid;
	fc_multirange->rangeCount = fc_range_count;

	fc_write_multirange_data(fc_multirange, fc_rangetyp, fc_range_count, fc_ranges);

	return fc_multirange;
}

/*
 * 获取多范围中第 i 个范围的边界值的偏移量。
 */
static uint32 fc_multirange_get_bounds_offset(const MultirangeType *fc_multirange, int32 fc_i)
{
	uint32	   *fc_items = MultirangeGetItemsPtr(fc_multirange);
	uint32		fc_offset = 0;

	/*
	 * 总结长度直至遇到一个偏移量。
	 */
	while (fc_i > 0)
	{
		fc_offset += MULTIRANGE_ITEM_GET_OFFLEN(fc_items[fc_i - 1]);
		if (MULTIRANGE_ITEM_HAS_OFF(fc_items[fc_i - 1]))
			break;
		fc_i--;
	}
	return fc_offset;
}

/*
 * 从多范围中获取第 i 个范围。
 */
RangeType * multirange_get_range(TypeCacheEntry *fc_rangetyp,
					 const MultirangeType *fc_multirange, int fc_i)
{
	uint32		fc_offset;
	uint8		fc_flags;
	Pointer		fc_begin,
				fc_ptr;
	int16		fc_typlen = fc_rangetyp->rngelemtype->typlen;
	char		fc_typalign = fc_rangetyp->rngelemtype->typalign;
	uint32		fc_len;
	RangeType  *fc_range;

	Assert(fc_i < fc_multirange->rangeCount);

	fc_offset = fc_multirange_get_bounds_offset(fc_multirange, fc_i);
	fc_flags = MultirangeGetFlagsPtr(fc_multirange)[fc_i];
	fc_ptr = fc_begin = MultirangeGetBoundariesPtr(fc_multirange, fc_typalign) + fc_offset;

	/*
	 * 计算边界值的大小。原则上，我们可以获取下一个范围
	 * 边界值的偏移量并相应地计算。但范围边界值是对齐的，
	 * 因此我们必须遍历这些值以获取确切的大小。
	 */
	if (RANGE_HAS_LBOUND(fc_flags))
		fc_ptr = (Pointer) att_addlength_pointer(fc_ptr, fc_typlen, fc_ptr);
	if (RANGE_HAS_UBOUND(fc_flags))
	{
		fc_ptr = (Pointer) att_align_pointer(fc_ptr, fc_typalign, fc_typlen, fc_ptr);
		fc_ptr = (Pointer) att_addlength_pointer(fc_ptr, fc_typlen, fc_ptr);
	}
	fc_len = (fc_ptr - fc_begin) + sizeof(RangeType) + sizeof(uint8);

	fc_range = palloc0(fc_len);
	SET_VARSIZE(fc_range, fc_len);
	fc_range->rangetypid = fc_rangetyp->type_id;

	memcpy(fc_range + 1, fc_begin, fc_ptr - fc_begin);
	*((uint8 *) (fc_range + 1) + (fc_ptr - fc_begin)) = fc_flags;

	return fc_range;
}

/*
 * 从多范围的第 i 个范围中获取边界。这是执行与
 * multirange_get_range() + range_deserialize() 相同操作的快捷方式，
 * 但执行的操作更少。
 */
void multirange_get_bounds(TypeCacheEntry *fc_rangetyp,
					  const MultirangeType *fc_multirange,
					  uint32 fc_i, RangeBound *fc_lower, RangeBound *fc_upper)
{
	uint32		fc_offset;
	uint8		fc_flags;
	Pointer		fc_ptr;
	int16		fc_typlen = fc_rangetyp->rngelemtype->typlen;
	char		fc_typalign = fc_rangetyp->rngelemtype->typalign;
	bool		fc_typbyval = fc_rangetyp->rngelemtype->typbyval;
	Datum		fc_lbound;
	Datum		fc_ubound;

	Assert(fc_i < fc_multirange->rangeCount);

	fc_offset = fc_multirange_get_bounds_offset(fc_multirange, fc_i);
	fc_flags = MultirangeGetFlagsPtr(fc_multirange)[fc_i];
	fc_ptr = MultirangeGetBoundariesPtr(fc_multirange, fc_typalign) + fc_offset;

	/* multirange 不能包含空范围 */
	Assert((fc_flags & RANGE_EMPTY) == 0);

	/* 如果有，获取下界 */
	if (RANGE_HAS_LBOUND(fc_flags))
	{
		/* att_align_pointer 在这里可能不是必要的 */
		fc_lbound = fetch_att(fc_ptr, fc_typbyval, fc_typlen);
		fc_ptr = (Pointer) att_addlength_pointer(fc_ptr, fc_typlen, fc_ptr);
	}
	else
		fc_lbound = (Datum) 0;

	/* 获取上限，如果有的话 */
	if (RANGE_HAS_UBOUND(fc_flags))
	{
		fc_ptr = (Pointer) att_align_pointer(fc_ptr, fc_typalign, fc_typlen, fc_ptr);
		fc_ubound = fetch_att(fc_ptr, fc_typbyval, fc_typlen);
		/* 不需要 att_addlength_pointer */
	}
	else
		fc_ubound = (Datum) 0;

	/* 发出结果 */
	fc_lower->val = fc_lbound;
	fc_lower->infinite = (fc_flags & RANGE_LB_INF) != 0;
	fc_lower->inclusive = (fc_flags & RANGE_LB_INC) != 0;
	fc_lower->lower = true;

	fc_upper->val = fc_ubound;
	fc_upper->infinite = (fc_flags & RANGE_UB_INF) != 0;
	fc_upper->inclusive = (fc_flags & RANGE_UB_INC) != 0;
	fc_upper->lower = false;
}

/*
 * 从多范围构造联合范围。
 */
RangeType * multirange_get_union_range(TypeCacheEntry *fc_rangetyp,
						   const MultirangeType *fc_mr)
{
	RangeBound	fc_lower,
				fc_upper,
				fc_tmp;

	if (MultirangeIsEmpty(fc_mr))
		return make_empty_range(fc_rangetyp);

	multirange_get_bounds(fc_rangetyp, fc_mr, 0, &fc_lower, &fc_tmp);
	multirange_get_bounds(fc_rangetyp, fc_mr, fc_mr->rangeCount - 1, &fc_tmp, &fc_upper);

	return make_range(fc_rangetyp, &fc_lower, &fc_upper, false);
}


/*
 * multirange_deserialize: 解构一个多范围值
 *
 * 注意：所给的多范围对象必须完全解冻；它不能有
 * 短 varlena 头。
 */
void multirange_deserialize(TypeCacheEntry *fc_rangetyp,
					   const MultirangeType *fc_multirange, int32 *fc_range_count,
					   RangeType ***fc_ranges)
{
	*fc_range_count = fc_multirange->rangeCount;

	/* 将每个 ShortRangeType 转换为 RangeType */
	if (*fc_range_count > 0)
	{
		int			fc_i;

		*fc_ranges = palloc(*fc_range_count * sizeof(RangeType *));
		for (fc_i = 0; fc_i < *fc_range_count; fc_i++)
			(*fc_ranges)[fc_i] = multirange_get_range(fc_rangetyp, fc_multirange, fc_i);
	}
	else
	{
		*fc_ranges = NULL;
	}
}

MultirangeType * make_empty_multirange(Oid fc_mltrngtypoid, TypeCacheEntry *fc_rangetyp)
{
	return make_multirange(fc_mltrngtypoid, fc_rangetyp, 0, NULL);
}

/*
 * 类似于 range_overlaps_internal()，但将范围边界而非
 * 范围作为参数。
 */
static bool fc_range_bounds_overlaps(TypeCacheEntry *fc_typcache,
					  RangeBound *fc_lower1, RangeBound *fc_upper1,
					  RangeBound *fc_lower2, RangeBound *fc_upper2)
{
	if (range_cmp_bounds(fc_typcache, fc_lower1, fc_lower2) >= 0 &&
		range_cmp_bounds(fc_typcache, fc_lower1, fc_upper2) <= 0)
		return true;

	if (range_cmp_bounds(fc_typcache, fc_lower2, fc_lower1) >= 0 &&
		range_cmp_bounds(fc_typcache, fc_lower2, fc_upper1) <= 0)
		return true;

	return false;
}

/*
 * 类似于 range_contains_internal()，但将范围边界而非
 * 范围作为参数。
 */
static bool fc_range_bounds_contains(TypeCacheEntry *fc_typcache,
					  RangeBound *fc_lower1, RangeBound *fc_upper1,
					  RangeBound *fc_lower2, RangeBound *fc_upper2)
{
	if (range_cmp_bounds(fc_typcache, fc_lower1, fc_lower2) <= 0 &&
		range_cmp_bounds(fc_typcache, fc_upper1, fc_upper2) >= 0)
		return true;

	return false;
}

/*
 * 检查给定的键是否与多范围中的任何范围匹配，使用二分查找。
 * 如果找不到所需的范围，则视为不匹配。当找到所需的范围时，
 * 比较函数仍然可以将其报告为匹配或不匹配。例如，如果我们
 * 搜索包含性，我们可能找到一个范围，它是重叠的但不包含键
 * 范围，这将被视为不匹配。
 */
static bool fc_multirange_bsearch_match(TypeCacheEntry *fc_typcache, const MultirangeType *fc_mr,
						 void *fc_key, multirange_bsearch_comparison fc_cmp_func)
{
	uint32		fc_l,
				fc_u,
				fc_idx;
	int			fc_comparison;
	bool		fc_match = false;

	fc_l = 0;
	fc_u = fc_mr->rangeCount;
	while (fc_l < fc_u)
	{
		RangeBound	fc_lower,
					fc_upper;

		fc_idx = (fc_l + fc_u) / 2;
		multirange_get_bounds(fc_typcache, fc_mr, fc_idx, &fc_lower, &fc_upper);
		fc_comparison = (*fc_cmp_func) (fc_typcache, &fc_lower, &fc_upper, fc_key, &fc_match);

		if (fc_comparison < 0)
			fc_u = fc_idx;
		else if (fc_comparison > 0)
			fc_l = fc_idx + 1;
		else
			return fc_match;
	}

	return false;
}

/*
 *----------------------------------------------------------
 * 通用函数
 *----------------------------------------------------------
 */

/*
 * 从零个或多个范围构造多范围值。由于这是一个
 * 变参函数，我们传递一个数组。该数组必须包含与
 * 我们的返回值匹配的范围，并且其中不能有 NULL。
 */
Datum multirange_constructor2(PG_FUNCTION_ARGS)
{
	Oid			fc_mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
	Oid			fc_rngtypid;
	TypeCacheEntry *fc_typcache;
	TypeCacheEntry *fc_rangetyp;
	ArrayType  *fc_rangeArray;
	int			fc_range_count;
	Datum	   *fc_elements;
	bool	   *fc_nulls;
	RangeType **fc_ranges;
	int			fc_dims;
	int			fc_i;

	fc_typcache = multirange_get_typcache(fcinfo, fc_mltrngtypid);
	fc_rangetyp = fc_typcache->rngtype;

	/*
	 * 一个不带参数的调用应该调用 multirange_constructor0，而不是
	 * 直接返回一个空范围。
	 */

	if (PG_NARGS() == 0)
		PG_RETURN_MULTIRANGE_P(make_multirange(fc_mltrngtypid, fc_rangetyp, 0, NULL));

	/*
	 * 这个检查应该由我们的签名确保，但我们还是做一下以防万一。
	 */

	if (PG_ARGISNULL(0))
		elog(ERROR,
			 "multirange values cannot contain null members");

	fc_rangeArray = PG_GETARG_ARRAYTYPE_P(0);

	fc_dims = ARR_NDIM(fc_rangeArray);
	if (fc_dims > 1)
		ereport(ERROR,
				(errcode(ERRCODE_CARDINALITY_VIOLATION),
				 errmsg("multiranges cannot be constructed from multidimensional arrays")));

	fc_rngtypid = ARR_ELEMTYPE(fc_rangeArray);
	if (fc_rngtypid != fc_rangetyp->type_id)
		elog(ERROR, "type %u does not match constructor type", fc_rngtypid);

	/*
	 * 小心：我们仍然可以使用零个范围被调用，如下所示：
	 * `int4multirange(variadic '{}'::int4range[])
	 */
	if (fc_dims == 0)
	{
		fc_range_count = 0;
		fc_ranges = NULL;
	}
	else
	{
		deconstruct_array(fc_rangeArray, fc_rngtypid, fc_rangetyp->typlen, fc_rangetyp->typbyval,
						  fc_rangetyp->typalign, &fc_elements, &fc_nulls, &fc_range_count);

		fc_ranges = palloc0(fc_range_count * sizeof(RangeType *));
		for (fc_i = 0; fc_i < fc_range_count; fc_i++)
		{
			if (fc_nulls[fc_i])
				ereport(ERROR,
						(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
						 errmsg("multirange values cannot contain null members")));

			/* make_multirange 将会自己复制 */
			fc_ranges[fc_i] = DatumGetRangeTypeP(fc_elements[fc_i]);
		}
	}

	PG_RETURN_MULTIRANGE_P(make_multirange(fc_mltrngtypid, fc_rangetyp, fc_range_count, fc_ranges));
}

/*
 * 从单个范围构造多范围值。如果我们能够
 * 仅仅为这种情况使用 multirange_constructor2，那就好了，
 * 但是我们需要一个非变参的单参数函数，以便能
 * 允许我们定义从范围到其多范围的 CAST。
 */
Datum multirange_constructor1(PG_FUNCTION_ARGS)
{
	Oid			fc_mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
	Oid			fc_rngtypid;
	TypeCacheEntry *fc_typcache;
	TypeCacheEntry *fc_rangetyp;
	RangeType  *fc_range;

	fc_typcache = multirange_get_typcache(fcinfo, fc_mltrngtypid);
	fc_rangetyp = fc_typcache->rngtype;

	/*
	 * 这个检查应该由我们的签名确保，但我们还是做一下以防万一。
	 */

	if (PG_ARGISNULL(0))
		elog(ERROR,
			 "multirange values cannot contain null members");

	fc_range = PG_GETARG_RANGE_P(0);

	/* 确保范围类型匹配。 */
	fc_rngtypid = RangeTypeGetOid(fc_range);
	if (fc_rngtypid != fc_rangetyp->type_id)
		elog(ERROR, "type %u does not match constructor type", fc_rngtypid);

	PG_RETURN_MULTIRANGE_P(make_multirange(fc_mltrngtypid, fc_rangetyp, 1, &fc_range));
}

/*
 * 构造函数与 multirange_constructor1 类似，但 opr_sanity 会愤怒
 * 如果同一内部函数处理多个参数个数不同的函数。
 */
Datum multirange_constructor0(PG_FUNCTION_ARGS)
{
	Oid			fc_mltrngtypid;
	TypeCacheEntry *fc_typcache;
	TypeCacheEntry *fc_rangetyp;

	/* 这应该始终在没有参数的情况下调用 */
	if (PG_NARGS() != 0)
		elog(ERROR,
			 "niladic multirange constructor must not receive arguments");

	fc_mltrngtypid = get_fn_expr_rettype(fcinfo->flinfo);
	fc_typcache = multirange_get_typcache(fcinfo, fc_mltrngtypid);
	fc_rangetyp = fc_typcache->rngtype;

	PG_RETURN_MULTIRANGE_P(make_multirange(fc_mltrngtypid, fc_rangetyp, 0, NULL));
}


/* multirange，multirange -> multirange 类型的函数 */

/* 多范围并集 */
Datum multirange_union(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;
	int32		fc_range_count1;
	int32		fc_range_count2;
	int32		fc_range_count3;
	RangeType **fc_ranges1;
	RangeType **fc_ranges2;
	RangeType **fc_ranges3;

	if (MultirangeIsEmpty(fc_mr1))
		PG_RETURN_MULTIRANGE_P(fc_mr2);
	if (MultirangeIsEmpty(fc_mr2))
		PG_RETURN_MULTIRANGE_P(fc_mr1);

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	multirange_deserialize(fc_typcache->rngtype, fc_mr1, &fc_range_count1, &fc_ranges1);
	multirange_deserialize(fc_typcache->rngtype, fc_mr2, &fc_range_count2, &fc_ranges2);

	fc_range_count3 = fc_range_count1 + fc_range_count2;
	fc_ranges3 = palloc0(fc_range_count3 * sizeof(RangeType *));
	memcpy(fc_ranges3, fc_ranges1, fc_range_count1 * sizeof(RangeType *));
	memcpy(fc_ranges3 + fc_range_count1, fc_ranges2, fc_range_count2 * sizeof(RangeType *));
	PG_RETURN_MULTIRANGE_P(make_multirange(fc_typcache->type_id, fc_typcache->rngtype,
										   fc_range_count3, fc_ranges3));
}

/* 多范围差集 */
Datum multirange_minus(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	Oid			fc_mltrngtypoid = MultirangeTypeGetOid(fc_mr1);
	TypeCacheEntry *fc_typcache;
	TypeCacheEntry *fc_rangetyp;
	int32		fc_range_count1;
	int32		fc_range_count2;
	RangeType **fc_ranges1;
	RangeType **fc_ranges2;

	fc_typcache = multirange_get_typcache(fcinfo, fc_mltrngtypoid);
	fc_rangetyp = fc_typcache->rngtype;

	if (MultirangeIsEmpty(fc_mr1) || MultirangeIsEmpty(fc_mr2))
		PG_RETURN_MULTIRANGE_P(fc_mr1);

	multirange_deserialize(fc_typcache->rngtype, fc_mr1, &fc_range_count1, &fc_ranges1);
	multirange_deserialize(fc_typcache->rngtype, fc_mr2, &fc_range_count2, &fc_ranges2);

	PG_RETURN_MULTIRANGE_P(multirange_minus_internal(fc_mltrngtypoid,
													 fc_rangetyp,
													 fc_range_count1,
													 fc_ranges1,
													 fc_range_count2,
													 fc_ranges2));
}

MultirangeType * multirange_minus_internal(Oid fc_mltrngtypoid, TypeCacheEntry *fc_rangetyp,
						  int32 fc_range_count1, RangeType **fc_ranges1,
						  int32 fc_range_count2, RangeType **fc_ranges2)
{
	RangeType  *fc_r1;
	RangeType  *fc_r2;
	RangeType **fc_ranges3;
	int32		fc_range_count3;
	int32		fc_i1;
	int32		fc_i2;

	/*
	 * 最坏的情况：ranges1 中的每个范围对 ranges2 中的某个范围
	 * 产生不同的切割。
	 */
	fc_ranges3 = palloc0((fc_range_count1 + fc_range_count2) * sizeof(RangeType *));
	fc_range_count3 = 0;

	/*
	 * 对于 mr1 中的每个范围，继续减去，直到它消失或
	 * mr2 中的范围超过它。减去后，我们将剩下的部分赋值回 r1。
	 * 在 mr1 和 mr2 中的并行进展类似于
	 * multirange_overlaps_multirange_internal。
	 */
	fc_r2 = fc_ranges2[0];
	for (fc_i1 = 0, fc_i2 = 0; fc_i1 < fc_range_count1; fc_i1++)
	{
		fc_r1 = fc_ranges1[fc_i1];

		/* 在 r2 << r1 时丢弃 r2 */
		while (fc_r2 != NULL && range_before_internal(fc_rangetyp, fc_r2, fc_r1))
		{
			fc_r2 = ++fc_i2 >= fc_range_count2 ? NULL : fc_ranges2[fc_i2];
		}

		while (fc_r2 != NULL)
		{
			if (range_split_internal(fc_rangetyp, fc_r1, fc_r2, &fc_ranges3[fc_range_count3], &fc_r1))
			{
				/*
				 * 如果 r2 从 r1 的中间位置切割，我们需要两个
				 * 输出
				 */
				fc_range_count3++;
				fc_r2 = ++fc_i2 >= fc_range_count2 ? NULL : fc_ranges2[fc_i2];
			}
			else if (range_overlaps_internal(fc_rangetyp, fc_r1, fc_r2))
			{
				/*
				 * 如果 r2 与 r1 重叠，则用 r1 - r2 替换 r1。
				 */
				fc_r1 = range_minus_internal(fc_rangetyp, fc_r1, fc_r2);

				/*
				 * 如果 r2 超过 r1，那么我们需要与之保持一致，以防
				 * 它碰到未来的 r1。否则我们需要保留 r1，以防
				 * 未来的 r2 碰到它。由于我们已经减去，没有
				 * 意义再使用 overright/overleft 调用。
				 */
				if (RangeIsEmpty(fc_r1) || range_before_internal(fc_rangetyp, fc_r1, fc_r2))
					break;
				else
					fc_r2 = ++fc_i2 >= fc_range_count2 ? NULL : fc_ranges2[fc_i2];
			}
			else
			{
				/*
				 * 这个以及所有未来的 r2 都在 r1 之后，所以保留下来。
				 * 此外，将 r1 剩下的部分赋值给结果。
				 */
				break;
			}
		}

		/*
		 * 其他任何内容都不能从 r1 中删除任何东西，所以保留它。
		 * 即使这里 r1 为空，make_multirange 也会将其删除。
		 */
		fc_ranges3[fc_range_count3++] = fc_r1;
	}

	return make_multirange(fc_mltrngtypoid, fc_rangetyp, fc_range_count3, fc_ranges3);
}

/* 多范围交集 */
Datum multirange_intersect(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	Oid			fc_mltrngtypoid = MultirangeTypeGetOid(fc_mr1);
	TypeCacheEntry *fc_typcache;
	TypeCacheEntry *fc_rangetyp;
	int32		fc_range_count1;
	int32		fc_range_count2;
	RangeType **fc_ranges1;
	RangeType **fc_ranges2;

	fc_typcache = multirange_get_typcache(fcinfo, fc_mltrngtypoid);
	fc_rangetyp = fc_typcache->rngtype;

	if (MultirangeIsEmpty(fc_mr1) || MultirangeIsEmpty(fc_mr2))
		PG_RETURN_MULTIRANGE_P(make_empty_multirange(fc_mltrngtypoid, fc_rangetyp));

	multirange_deserialize(fc_rangetyp, fc_mr1, &fc_range_count1, &fc_ranges1);
	multirange_deserialize(fc_rangetyp, fc_mr2, &fc_range_count2, &fc_ranges2);

	PG_RETURN_MULTIRANGE_P(multirange_intersect_internal(fc_mltrngtypoid,
														 fc_rangetyp,
														 fc_range_count1,
														 fc_ranges1,
														 fc_range_count2,
														 fc_ranges2));
}

MultirangeType * multirange_intersect_internal(Oid fc_mltrngtypoid, TypeCacheEntry *fc_rangetyp,
							  int32 fc_range_count1, RangeType **fc_ranges1,
							  int32 fc_range_count2, RangeType **fc_ranges2)
{
	RangeType  *fc_r1;
	RangeType  *fc_r2;
	RangeType **fc_ranges3;
	int32		fc_range_count3;
	int32		fc_i1;
	int32		fc_i2;

	if (fc_range_count1 == 0 || fc_range_count2 == 0)
		return make_multirange(fc_mltrngtypoid, fc_rangetyp, 0, NULL);

	/* -----------------------------------------------
	 * 最坏情况下的拼接模式如下：
	 *
	 * mr1: --- --- --- ---
	 * mr2:   --- --- ---
	 * mr3:   - - - - - -
	 *
	 * 这似乎是 range_count1 + range_count2 - 1，
	 * 但多一个也无妨。
	 * -----------------------------------------------
	 */
	fc_ranges3 = palloc0((fc_range_count1 + fc_range_count2) * sizeof(RangeType *));
	fc_range_count3 = 0;

	/*
	 * 对于 mr1 中的每个范围，保持交集直到 mr2 中的范围
	 * 超过它。mr1 和 mr2 的并行进展类似于
	 * multirange_minus_multirange_internal，但我们不必将结果分配回 r1。
	 */
	fc_r2 = fc_ranges2[0];
	for (fc_i1 = 0, fc_i2 = 0; fc_i1 < fc_range_count1; fc_i1++)
	{
		fc_r1 = fc_ranges1[fc_i1];

		/* 在 r2 << r1 时丢弃 r2 */
		while (fc_r2 != NULL && range_before_internal(fc_rangetyp, fc_r2, fc_r1))
		{
			fc_r2 = ++fc_i2 >= fc_range_count2 ? NULL : fc_ranges2[fc_i2];
		}

		while (fc_r2 != NULL)
		{
			if (range_overlaps_internal(fc_rangetyp, fc_r1, fc_r2))
			{
				/* 保留重叠部分 */
				fc_ranges3[fc_range_count3++] = range_intersect_internal(fc_rangetyp, fc_r1, fc_r2);

				/* 如果我们“用完”了 r2，去下一个... */
				if (range_overleft_internal(fc_rangetyp, fc_r2, fc_r1))
					fc_r2 = ++fc_i2 >= fc_range_count2 ? NULL : fc_ranges2[fc_i2];

				/* ...否则去下一个 r1 */
				else
					break;
			}
			else
				/* 我们已经过了 r1，所以移动到下一个 */
				break;
		}

		/* 如果我们没有 r2，可以没有更多交集 */
		if (fc_r2 == NULL)
			break;
	}

	return make_multirange(fc_mltrngtypoid, fc_rangetyp, fc_range_count3, fc_ranges3);
}

/*
 * range_agg_transfn：组合相邻/重叠的范围。
 *
 * 我们在这里所做的只是将输入范围收集到一个数组中
 * 以便 finalfn 可以对其进行排序和组合。
 */
Datum range_agg_transfn(PG_FUNCTION_ARGS)
{
	MemoryContext fc_aggContext;
	Oid			fc_rngtypoid;
	ArrayBuildState *fc_state;

	if (!AggCheckCallContext(fcinfo, &fc_aggContext))
		elog(ERROR, "range_agg_transfn called in non-aggregate context");

	fc_rngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
	if (!type_is_range(fc_rngtypoid))
		elog(ERROR, "range_agg must be called with a range");

	if (PG_ARGISNULL(0))
		fc_state = initArrayResult(fc_rngtypoid, fc_aggContext, false);
	else
		fc_state = (ArrayBuildState *) PG_GETARG_POINTER(0);

	/* 跳过 NULL */
	if (!PG_ARGISNULL(1))
		accumArrayResult(fc_state, PG_GETARG_DATUM(1), false, fc_rngtypoid, fc_aggContext);

	PG_RETURN_POINTER(fc_state);
}

/*
 * range_agg_finalfn：使用我们的内部数组合并相邻的范围。
 *
 * 由 range_agg_finalfn(anyrange) 和
 * multirange_agg_finalfn(anymultirange) 共享。
 */
Datum range_agg_finalfn(PG_FUNCTION_ARGS)
{
	MemoryContext fc_aggContext;
	Oid			fc_mltrngtypoid;
	TypeCacheEntry *fc_typcache;
	ArrayBuildState *fc_state;
	int32		fc_range_count;
	RangeType **fc_ranges;
	int			fc_i;

	if (!AggCheckCallContext(fcinfo, &fc_aggContext))
		elog(ERROR, "range_agg_finalfn called in non-aggregate context");

	fc_state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0);
	if (fc_state == NULL)
		/* 这应该不可能，但以防万一.... */
		PG_RETURN_NULL();

	/* 如果我们有零个输入，也返回 NULL，就像其他聚合函数一样 */
	fc_range_count = fc_state->nelems;
	if (fc_range_count == 0)
		PG_RETURN_NULL();

	fc_mltrngtypoid = get_fn_expr_rettype(fcinfo->flinfo);
	fc_typcache = multirange_get_typcache(fcinfo, fc_mltrngtypoid);

	fc_ranges = palloc0(fc_range_count * sizeof(RangeType *));
	for (fc_i = 0; fc_i < fc_range_count; fc_i++)
		fc_ranges[fc_i] = DatumGetRangeTypeP(fc_state->dvalues[fc_i]);

	PG_RETURN_MULTIRANGE_P(make_multirange(fc_mltrngtypoid, fc_typcache->rngtype, fc_range_count, fc_ranges));
}

/*
 * multirange_agg_transfn：组合相邻/重叠的多范围。
 *
 * 我们在这里所做的只是将输入多范围的范围收集到一个数组中，以便
 * finalfn 可以对其进行排序和组合。
 */
Datum multirange_agg_transfn(PG_FUNCTION_ARGS)
{
	MemoryContext fc_aggContext;
	Oid			fc_mltrngtypoid;
	TypeCacheEntry *fc_typcache;
	TypeCacheEntry *fc_rngtypcache;
	ArrayBuildState *fc_state;

	if (!AggCheckCallContext(fcinfo, &fc_aggContext))
		elog(ERROR, "multirange_agg_transfn called in non-aggregate context");

	fc_mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
	if (!type_is_multirange(fc_mltrngtypoid))
		elog(ERROR, "range_agg must be called with a multirange");

	fc_typcache = multirange_get_typcache(fcinfo, fc_mltrngtypoid);
	fc_rngtypcache = fc_typcache->rngtype;

	if (PG_ARGISNULL(0))
		fc_state = initArrayResult(fc_rngtypcache->type_id, fc_aggContext, false);
	else
		fc_state = (ArrayBuildState *) PG_GETARG_POINTER(0);

	/* 跳过 NULL */
	if (!PG_ARGISNULL(1))
	{
		MultirangeType *fc_current;
		int32		fc_range_count;
		RangeType **fc_ranges;

		fc_current = PG_GETARG_MULTIRANGE_P(1);
		multirange_deserialize(fc_rngtypcache, fc_current, &fc_range_count, &fc_ranges);
		if (fc_range_count == 0)
		{
			/*
			 * 添加一个空范围，以便我们得到一个空结果（而不是 null
			 * 结果）。
			 */
			accumArrayResult(fc_state,
							 RangeTypePGetDatum(make_empty_range(fc_rngtypcache)),
							 false, fc_rngtypcache->type_id, fc_aggContext);
		}
		else
		{
			for (int32 fc_i = 0; fc_i < fc_range_count; fc_i++)
				accumArrayResult(fc_state, RangeTypePGetDatum(fc_ranges[fc_i]), false, fc_rngtypcache->type_id, fc_aggContext);
		}
	}

	PG_RETURN_POINTER(fc_state);
}

Datum multirange_intersect_agg_transfn(PG_FUNCTION_ARGS)
{
	MemoryContext fc_aggContext;
	Oid			fc_mltrngtypoid;
	TypeCacheEntry *fc_typcache;
	MultirangeType *fc_result;
	MultirangeType *fc_current;
	int32		fc_range_count1;
	int32		fc_range_count2;
	RangeType **fc_ranges1;
	RangeType **fc_ranges2;

	if (!AggCheckCallContext(fcinfo, &fc_aggContext))
		elog(ERROR, "multirange_intersect_agg_transfn called in non-aggregate context");

	fc_mltrngtypoid = get_fn_expr_argtype(fcinfo->flinfo, 1);
	if (!type_is_multirange(fc_mltrngtypoid))
		elog(ERROR, "range_intersect_agg must be called with a multirange");

	fc_typcache = multirange_get_typcache(fcinfo, fc_mltrngtypoid);

	/* 严格性确保这些是非空 */
	fc_result = PG_GETARG_MULTIRANGE_P(0);
	fc_current = PG_GETARG_MULTIRANGE_P(1);

	multirange_deserialize(fc_typcache->rngtype, fc_result, &fc_range_count1, &fc_ranges1);
	multirange_deserialize(fc_typcache->rngtype, fc_current, &fc_range_count2, &fc_ranges2);

	fc_result = multirange_intersect_internal(fc_mltrngtypoid,
										   fc_typcache->rngtype,
										   fc_range_count1,
										   fc_ranges1,
										   fc_range_count2,
										   fc_ranges2);
	PG_RETURN_RANGE_P(fc_result);
}


/* multirange -> 元素类型函数 */

/* 提取下限值 */
Datum multirange_lower(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	TypeCacheEntry *fc_typcache;
	RangeBound	fc_lower;
	RangeBound	fc_upper;

	if (MultirangeIsEmpty(fc_mr))
		PG_RETURN_NULL();

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	multirange_get_bounds(fc_typcache->rngtype, fc_mr, 0,
						  &fc_lower, &fc_upper);

	if (!fc_lower.infinite)
		PG_RETURN_DATUM(fc_lower.val);
	else
		PG_RETURN_NULL();
}

/* 提取上限值 */
Datum multirange_upper(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	TypeCacheEntry *fc_typcache;
	RangeBound	fc_lower;
	RangeBound	fc_upper;

	if (MultirangeIsEmpty(fc_mr))
		PG_RETURN_NULL();

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	multirange_get_bounds(fc_typcache->rngtype, fc_mr, fc_mr->rangeCount - 1,
						  &fc_lower, &fc_upper);

	if (!fc_upper.infinite)
		PG_RETURN_DATUM(fc_upper.val);
	else
		PG_RETURN_NULL();
}


/* multirange -> 布尔函数 */

/* multirange 为空吗？ */
Datum multirange_empty(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);

	PG_RETURN_BOOL(MultirangeIsEmpty(fc_mr));
}

/* 下限包含吗？ */
Datum multirange_lower_inc(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	TypeCacheEntry *fc_typcache;
	RangeBound	fc_lower;
	RangeBound	fc_upper;

	if (MultirangeIsEmpty(fc_mr))
		PG_RETURN_BOOL(false);

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));
	multirange_get_bounds(fc_typcache->rngtype, fc_mr, 0,
						  &fc_lower, &fc_upper);

	PG_RETURN_BOOL(fc_lower.inclusive);
}

/* 上限包含吗？ */
Datum multirange_upper_inc(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	TypeCacheEntry *fc_typcache;
	RangeBound	fc_lower;
	RangeBound	fc_upper;

	if (MultirangeIsEmpty(fc_mr))
		PG_RETURN_BOOL(false);

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));
	multirange_get_bounds(fc_typcache->rngtype, fc_mr, fc_mr->rangeCount - 1,
						  &fc_lower, &fc_upper);

	PG_RETURN_BOOL(fc_upper.inclusive);
}

/* 下限是无限吗？ */
Datum multirange_lower_inf(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	TypeCacheEntry *fc_typcache;
	RangeBound	fc_lower;
	RangeBound	fc_upper;

	if (MultirangeIsEmpty(fc_mr))
		PG_RETURN_BOOL(false);

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));
	multirange_get_bounds(fc_typcache->rngtype, fc_mr, 0,
						  &fc_lower, &fc_upper);

	PG_RETURN_BOOL(fc_lower.infinite);
}

/* 上限是无限吗？ */
Datum multirange_upper_inf(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	TypeCacheEntry *fc_typcache;
	RangeBound	fc_lower;
	RangeBound	fc_upper;

	if (MultirangeIsEmpty(fc_mr))
		PG_RETURN_BOOL(false);

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));
	multirange_get_bounds(fc_typcache->rngtype, fc_mr, fc_mr->rangeCount - 1,
						  &fc_lower, &fc_upper);

	PG_RETURN_BOOL(fc_upper.infinite);
}



/* multirange，元素 -> 布尔函数 */

/* 包含吗？ */
Datum multirange_contains_elem(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	Datum		fc_val = PG_GETARG_DATUM(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(multirange_contains_elem_internal(fc_typcache->rngtype, fc_mr, fc_val));
}

/* 被包含吗？ */
Datum elem_contained_by_multirange(PG_FUNCTION_ARGS)
{
	Datum		fc_val = PG_GETARG_DATUM(0);
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(multirange_contains_elem_internal(fc_typcache->rngtype, fc_mr, fc_val));
}

/*
 * 用于检查多范围的任意范围是否包含给定
 * 键元素的比较函数，通过二分搜索。
 */
static int fc_multirange_elem_bsearch_comparison(TypeCacheEntry *fc_typcache,
								   RangeBound *fc_lower, RangeBound *fc_upper,
								   void *fc_key, bool *fc_match)
{
	Datum		fc_val = *((Datum *) fc_key);
	int			fc_cmp;

	if (!fc_lower->infinite)
	{
		fc_cmp = DatumGetInt32(FunctionCall2Coll(&fc_typcache->rng_cmp_proc_finfo,
											  fc_typcache->rng_collation,
											  fc_lower->val, fc_val));
		if (fc_cmp > 0 || (fc_cmp == 0 && !fc_lower->inclusive))
			return -1;
	}

	if (!fc_upper->infinite)
	{
		fc_cmp = DatumGetInt32(FunctionCall2Coll(&fc_typcache->rng_cmp_proc_finfo,
											  fc_typcache->rng_collation,
											  fc_upper->val, fc_val));
		if (fc_cmp < 0 || (fc_cmp == 0 && !fc_upper->inclusive))
			return 1;
	}

	*fc_match = true;
	return 0;
}

/*
 * 测试多范围 mr 是否包含特定元素值。
 */
bool multirange_contains_elem_internal(TypeCacheEntry *fc_rangetyp,
								  const MultirangeType *fc_mr, Datum fc_val)
{
	if (MultirangeIsEmpty(fc_mr))
		return false;

	return fc_multirange_bsearch_match(fc_rangetyp, fc_mr, &fc_val,
									fc_multirange_elem_bsearch_comparison);
}

/* multirange, range -> bool 函数 */

/* 包含吗？ */
Datum multirange_contains_range(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	RangeType  *fc_r = PG_GETARG_RANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(multirange_contains_range_internal(fc_typcache->rngtype, fc_mr, fc_r));
}

Datum range_contains_multirange(PG_FUNCTION_ARGS)
{
	RangeType  *fc_r = PG_GETARG_RANGE_P(0);
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_contains_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

/* 被包含吗？ */
Datum range_contained_by_multirange(PG_FUNCTION_ARGS)
{
	RangeType  *fc_r = PG_GETARG_RANGE_P(0);
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(multirange_contains_range_internal(fc_typcache->rngtype, fc_mr, fc_r));
}

Datum multirange_contained_by_range(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	RangeType  *fc_r = PG_GETARG_RANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_contains_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

/*
 * 比较函数，用于检查 multirange 中的任何范围是否包含给定的
 * 键范围，使用二分查找。
 */
static int fc_multirange_range_contains_bsearch_comparison(TypeCacheEntry *fc_typcache,
											 RangeBound *fc_lower, RangeBound *fc_upper,
											 void *fc_key, bool *fc_match)
{
	RangeBound *fc_keyLower = (RangeBound *) fc_key;
	RangeBound *fc_keyUpper = (RangeBound *) fc_key + 1;

	/* 检查键范围是否严格在左侧或右侧 */
	if (range_cmp_bounds(fc_typcache, fc_keyUpper, fc_lower) < 0)
		return -1;
	if (range_cmp_bounds(fc_typcache, fc_keyLower, fc_upper) > 0)
		return 1;

	/*
	 * 在这一点上，我们发现了重叠范围。但我们必须检查它
	 * 是否确实包含键范围。无论如何，我们必须在这里停止搜索，
	 * 因为 multirange 只包含不重叠的范围。
	 */
	*fc_match = fc_range_bounds_contains(fc_typcache, fc_lower, fc_upper, fc_keyLower, fc_keyUpper);

	return 0;
}

/*
 * 测试 multirange mr 是否包含特定范围 r。
 */
bool multirange_contains_range_internal(TypeCacheEntry *fc_rangetyp,
								   const MultirangeType *fc_mr,
								   const RangeType *fc_r)
{
	RangeBound	fc_bounds[2];
	bool		fc_empty;

	/*
	 * 每个 multirange 包含无限个空范围，甚至一个
	 * 空的范围。
	 */
	if (RangeIsEmpty(fc_r))
		return true;

	if (MultirangeIsEmpty(fc_mr))
		return false;

	range_deserialize(fc_rangetyp, fc_r, &fc_bounds[0], &fc_bounds[1], &fc_empty);
	Assert(!fc_empty);

	return fc_multirange_bsearch_match(fc_rangetyp, fc_mr, fc_bounds,
									fc_multirange_range_contains_bsearch_comparison);
}

/*
 * 测试范围 r 是否包含 multirange mr。
 */
bool range_contains_multirange_internal(TypeCacheEntry *fc_rangetyp,
								   const RangeType *fc_r,
								   const MultirangeType *fc_mr)
{
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2,
				fc_tmp;
	bool		fc_empty;

	/*
	 * 每个范围包含无限个空 multirange，甚至一个
	 * 空的 multirange。
	 */
	if (MultirangeIsEmpty(fc_mr))
		return true;

	if (RangeIsEmpty(fc_r))
		return false;

	/* 范围包含 multirange 当且仅当它包含其并集范围。 */
	range_deserialize(fc_rangetyp, fc_r, &fc_lower1, &fc_upper1, &fc_empty);
	Assert(!fc_empty);
	multirange_get_bounds(fc_rangetyp, fc_mr, 0, &fc_lower2, &fc_tmp);
	multirange_get_bounds(fc_rangetyp, fc_mr, fc_mr->rangeCount - 1, &fc_tmp, &fc_upper2);

	return fc_range_bounds_contains(fc_rangetyp, &fc_lower1, &fc_upper1, &fc_lower2, &fc_upper2);
}


/* multirange, multirange -> bool 函数 */

/* 相等（内部版本） */
bool multirange_eq_internal(TypeCacheEntry *fc_rangetyp,
					   const MultirangeType *fc_mr1,
					   const MultirangeType *fc_mr2)
{
	int32		fc_range_count_1;
	int32		fc_range_count_2;
	int32		fc_i;
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;

	/* 不同类型应该通过 ANYMULTIRANGE 匹配规则防止出现 */
	if (MultirangeTypeGetOid(fc_mr1) != MultirangeTypeGetOid(fc_mr2))
		elog(ERROR, "multirange types do not match");

	fc_range_count_1 = fc_mr1->rangeCount;
	fc_range_count_2 = fc_mr2->rangeCount;

	if (fc_range_count_1 != fc_range_count_2)
		return false;

	for (fc_i = 0; fc_i < fc_range_count_1; fc_i++)
	{
		multirange_get_bounds(fc_rangetyp, fc_mr1, fc_i, &fc_lower1, &fc_upper1);
		multirange_get_bounds(fc_rangetyp, fc_mr2, fc_i, &fc_lower2, &fc_upper2);

		if (range_cmp_bounds(fc_rangetyp, &fc_lower1, &fc_lower2) != 0 ||
			range_cmp_bounds(fc_rangetyp, &fc_upper1, &fc_upper2) != 0)
			return false;
	}

	return true;
}

/* equality */
Datum multirange_eq(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	PG_RETURN_BOOL(multirange_eq_internal(fc_typcache->rngtype, fc_mr1, fc_mr2));
}

/* 不相等（内部版本） */
bool multirange_ne_internal(TypeCacheEntry *fc_rangetyp,
					   const MultirangeType *fc_mr1,
					   const MultirangeType *fc_mr2)
{
	return (!multirange_eq_internal(fc_rangetyp, fc_mr1, fc_mr2));
}

/* 不相等 */
Datum multirange_ne(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	PG_RETURN_BOOL(multirange_ne_internal(fc_typcache->rngtype, fc_mr1, fc_mr2));
}

/* 是否重叠？ */
Datum range_overlaps_multirange(PG_FUNCTION_ARGS)
{
	RangeType  *fc_r = PG_GETARG_RANGE_P(0);
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_overlaps_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

Datum multirange_overlaps_range(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	RangeType  *fc_r = PG_GETARG_RANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_overlaps_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

Datum multirange_overlaps_multirange(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	PG_RETURN_BOOL(multirange_overlaps_multirange_internal(fc_typcache->rngtype, fc_mr1, fc_mr2));
}

/*
 * 比较函数，用于检查 multirange 中的任何范围是否与给定
 * 键范围重叠，使用二分查找。
 */
static int fc_multirange_range_overlaps_bsearch_comparison(TypeCacheEntry *fc_typcache,
											 RangeBound *fc_lower, RangeBound *fc_upper,
											 void *fc_key, bool *fc_match)
{
	RangeBound *fc_keyLower = (RangeBound *) fc_key;
	RangeBound *fc_keyUpper = (RangeBound *) fc_key + 1;

	if (range_cmp_bounds(fc_typcache, fc_keyUpper, fc_lower) < 0)
		return -1;
	if (range_cmp_bounds(fc_typcache, fc_keyLower, fc_upper) > 0)
		return 1;

	*fc_match = true;
	return 0;
}

bool range_overlaps_multirange_internal(TypeCacheEntry *fc_rangetyp,
								   const RangeType *fc_r,
								   const MultirangeType *fc_mr)
{
	RangeBound	fc_bounds[2];
	bool		fc_empty;

	/*
	 * 空范围从不重叠，即使是与空范围重叠。（这似乎很奇怪，因为 
	 * 它们确实相互包含，但我们想遵循范围的工作方式。）
	 */
	if (RangeIsEmpty(fc_r) || MultirangeIsEmpty(fc_mr))
		return false;

	range_deserialize(fc_rangetyp, fc_r, &fc_bounds[0], &fc_bounds[1], &fc_empty);
	Assert(!fc_empty);

	return fc_multirange_bsearch_match(fc_rangetyp, fc_mr, fc_bounds,
									fc_multirange_range_overlaps_bsearch_comparison);
}

bool multirange_overlaps_multirange_internal(TypeCacheEntry *fc_rangetyp,
										const MultirangeType *fc_mr1,
										const MultirangeType *fc_mr2)
{
	int32		fc_range_count1;
	int32		fc_range_count2;
	int32		fc_i1;
	int32		fc_i2;
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;

	/*
	 * 空范围从不重叠，即使是与空范围重叠。（这似乎很奇怪，因为 
	 * 它们确实相互包含，但我们想遵循范围的工作方式。）
	 */
	if (MultirangeIsEmpty(fc_mr1) || MultirangeIsEmpty(fc_mr2))
		return false;

	fc_range_count1 = fc_mr1->rangeCount;
	fc_range_count2 = fc_mr2->rangeCount;

	/*
	 * mr1 中的每个范围都有机会与 mr2 中的范围重叠，但
	 * 我们可以利用它们的顺序来避免 O(n^2)。这类似于
	 * range_overlaps_multirange，其中 r1 : r2 :: mrr : r，但如果我们
	 * 与 r 发现不到重叠，我们就完成了，而在这里如果我们与 r2
	 * 发现不到重叠，我们尝试下一个 r2。
	 */
	fc_i1 = 0;
	multirange_get_bounds(fc_rangetyp, fc_mr1, fc_i1, &fc_lower1, &fc_upper1);
	for (fc_i1 = 0, fc_i2 = 0; fc_i2 < fc_range_count2; fc_i2++)
	{
		multirange_get_bounds(fc_rangetyp, fc_mr2, fc_i2, &fc_lower2, &fc_upper2);

		/* 在 r1 << r2 的情况下丢弃 r1 */
		while (range_cmp_bounds(fc_rangetyp, &fc_upper1, &fc_lower2) < 0)
		{
			if (++fc_i1 >= fc_range_count1)
				return false;
			multirange_get_bounds(fc_rangetyp, fc_mr1, fc_i1, &fc_lower1, &fc_upper1);
		}

		/*
		 * 如果 r1 && r2，我们就完成了，否则我们未能找到 r2 的重叠，
		 * 所以继续下一个。
		 */
		if (fc_range_bounds_overlaps(fc_rangetyp, &fc_lower1, &fc_upper1, &fc_lower2, &fc_upper2))
			return true;
	}

	/* 我们查看了所有的 mr2，但没有找到重叠 */
	return false;
}

/* 不延伸到右侧吗？ */
bool range_overleft_multirange_internal(TypeCacheEntry *fc_rangetyp,
								   const RangeType *fc_r,
								   const MultirangeType *fc_mr)
{
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;
	bool		fc_empty;

	if (RangeIsEmpty(fc_r) || MultirangeIsEmpty(fc_mr))
		PG_RETURN_BOOL(false);


	range_deserialize(fc_rangetyp, fc_r, &fc_lower1, &fc_upper1, &fc_empty);
	Assert(!fc_empty);
	multirange_get_bounds(fc_rangetyp, fc_mr, fc_mr->rangeCount - 1,
						  &fc_lower2, &fc_upper2);

	PG_RETURN_BOOL(range_cmp_bounds(fc_rangetyp, &fc_upper1, &fc_upper2) <= 0);
}

Datum range_overleft_multirange(PG_FUNCTION_ARGS)
{
	RangeType  *fc_r = PG_GETARG_RANGE_P(0);
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_overleft_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

Datum multirange_overleft_range(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	RangeType  *fc_r = PG_GETARG_RANGE_P(1);
	TypeCacheEntry *fc_typcache;
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;
	bool		fc_empty;

	if (MultirangeIsEmpty(fc_mr) || RangeIsEmpty(fc_r))
		PG_RETURN_BOOL(false);

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	multirange_get_bounds(fc_typcache->rngtype, fc_mr, fc_mr->rangeCount - 1,
						  &fc_lower1, &fc_upper1);
	range_deserialize(fc_typcache->rngtype, fc_r, &fc_lower2, &fc_upper2, &fc_empty);
	Assert(!fc_empty);

	PG_RETURN_BOOL(range_cmp_bounds(fc_typcache->rngtype, &fc_upper1, &fc_upper2) <= 0);
}

Datum multirange_overleft_multirange(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;

	if (MultirangeIsEmpty(fc_mr1) || MultirangeIsEmpty(fc_mr2))
		PG_RETURN_BOOL(false);

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	multirange_get_bounds(fc_typcache->rngtype, fc_mr1, fc_mr1->rangeCount - 1,
						  &fc_lower1, &fc_upper1);
	multirange_get_bounds(fc_typcache->rngtype, fc_mr2, fc_mr2->rangeCount - 1,
						  &fc_lower2, &fc_upper2);

	PG_RETURN_BOOL(range_cmp_bounds(fc_typcache->rngtype, &fc_upper1, &fc_upper2) <= 0);
}

/* 不延伸到左侧吗？ */
bool range_overright_multirange_internal(TypeCacheEntry *fc_rangetyp,
									const RangeType *fc_r,
									const MultirangeType *fc_mr)
{
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;
	bool		fc_empty;

	if (RangeIsEmpty(fc_r) || MultirangeIsEmpty(fc_mr))
		PG_RETURN_BOOL(false);

	range_deserialize(fc_rangetyp, fc_r, &fc_lower1, &fc_upper1, &fc_empty);
	Assert(!fc_empty);
	multirange_get_bounds(fc_rangetyp, fc_mr, 0, &fc_lower2, &fc_upper2);

	return (range_cmp_bounds(fc_rangetyp, &fc_lower1, &fc_lower2) >= 0);
}

Datum range_overright_multirange(PG_FUNCTION_ARGS)
{
	RangeType  *fc_r = PG_GETARG_RANGE_P(0);
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_overright_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

Datum multirange_overright_range(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	RangeType  *fc_r = PG_GETARG_RANGE_P(1);
	TypeCacheEntry *fc_typcache;
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;
	bool		fc_empty;

	if (MultirangeIsEmpty(fc_mr) || RangeIsEmpty(fc_r))
		PG_RETURN_BOOL(false);

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	multirange_get_bounds(fc_typcache->rngtype, fc_mr, 0, &fc_lower1, &fc_upper1);
	range_deserialize(fc_typcache->rngtype, fc_r, &fc_lower2, &fc_upper2, &fc_empty);
	Assert(!fc_empty);

	PG_RETURN_BOOL(range_cmp_bounds(fc_typcache->rngtype, &fc_lower1, &fc_lower2) >= 0);
}

Datum multirange_overright_multirange(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;

	if (MultirangeIsEmpty(fc_mr1) || MultirangeIsEmpty(fc_mr2))
		PG_RETURN_BOOL(false);

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	multirange_get_bounds(fc_typcache->rngtype, fc_mr1, 0, &fc_lower1, &fc_upper1);
	multirange_get_bounds(fc_typcache->rngtype, fc_mr2, 0, &fc_lower2, &fc_upper2);

	PG_RETURN_BOOL(range_cmp_bounds(fc_typcache->rngtype, &fc_lower1, &fc_lower2) >= 0);
}

/* 包含吗？ */
Datum multirange_contains_multirange(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	PG_RETURN_BOOL(multirange_contains_multirange_internal(fc_typcache->rngtype, fc_mr1, fc_mr2));
}

/* 被包含吗？ */
Datum multirange_contained_by_multirange(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	PG_RETURN_BOOL(multirange_contains_multirange_internal(fc_typcache->rngtype, fc_mr2, fc_mr1));
}

/*
 * 测试 multirange mr1 是否包含另一个 multirange mr2 中的每个范围。
 */
bool multirange_contains_multirange_internal(TypeCacheEntry *fc_rangetyp,
										const MultirangeType *fc_mr1,
										const MultirangeType *fc_mr2)
{
	int32		fc_range_count1 = fc_mr1->rangeCount;
	int32		fc_range_count2 = fc_mr2->rangeCount;
	int			fc_i1,
				fc_i2;
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;

	/*
	 * 我们对空范围遵循与范围相同的逻辑：- 一个空 multirange
	 * 包含一个空范围/multirange。- 一个空 multirange 不能包含
	 * 任何其他范围/multirange。- 一个空 multirange 被任何
	 * 其他范围/multirange 所包含。
	 */

	if (fc_range_count2 == 0)
		return true;
	if (fc_range_count1 == 0)
		return false;

	/*
	 * mr2 中的每个范围必须被 mr1 中的某个范围包含。为了避免
	 * O(n^2)，我们同时遍历这两个范围。
	 */
	fc_i1 = 0;
	multirange_get_bounds(fc_rangetyp, fc_mr1, fc_i1, &fc_lower1, &fc_upper1);
	for (fc_i2 = 0; fc_i2 < fc_range_count2; fc_i2++)
	{
		multirange_get_bounds(fc_rangetyp, fc_mr2, fc_i2, &fc_lower2, &fc_upper2);

		/* 在 r1 << r2 的情况下丢弃 r1 */
		while (range_cmp_bounds(fc_rangetyp, &fc_upper1, &fc_lower2) < 0)
		{
			if (++fc_i1 >= fc_range_count1)
				return false;
			multirange_get_bounds(fc_rangetyp, fc_mr1, fc_i1, &fc_lower1, &fc_upper1);
		}

		/*
		 * 如果 r1 @> r2，转到下一个 r2，否则返回 false（因为每个
		 * r1[n] 和 r1[n+1] 必须有一个间隙）。请注意，如果没有进行标准化，这将给出奇怪的
		 * 答案，例如，使用自定义的 int2multirange {[1,1], [2,2]}，存在一个“间隙”。
		 * 但这与其他范围操作是一致的，例如 '[1,1]'::int2range -|-
		 * '[2,2]'::int2range 为假。
		 */
		if (!fc_range_bounds_contains(fc_rangetyp, &fc_lower1, &fc_upper1,
								   &fc_lower2, &fc_upper2))
			return false;
	}

	/* mr2 中的所有范围都满足 */
	return true;
}

/* 严格在左侧吗？ */
Datum range_before_multirange(PG_FUNCTION_ARGS)
{
	RangeType  *fc_r = PG_GETARG_RANGE_P(0);
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_before_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

Datum multirange_before_range(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	RangeType  *fc_r = PG_GETARG_RANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_after_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

Datum multirange_before_multirange(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	PG_RETURN_BOOL(multirange_before_multirange_internal(fc_typcache->rngtype, fc_mr1, fc_mr2));
}

/* 严格在右侧吗？ */
Datum range_after_multirange(PG_FUNCTION_ARGS)
{
	RangeType  *fc_r = PG_GETARG_RANGE_P(0);
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_after_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

Datum multirange_after_range(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	RangeType  *fc_r = PG_GETARG_RANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_before_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

Datum multirange_after_multirange(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	PG_RETURN_BOOL(multirange_before_multirange_internal(fc_typcache->rngtype, fc_mr2, fc_mr1));
}

/* 严格在左边吗? (内部版本) */
bool range_before_multirange_internal(TypeCacheEntry *fc_rangetyp,
								 const RangeType *fc_r,
								 const MultirangeType *fc_mr)
{
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;
	bool		fc_empty;

	if (RangeIsEmpty(fc_r) || MultirangeIsEmpty(fc_mr))
		return false;

	range_deserialize(fc_rangetyp, fc_r, &fc_lower1, &fc_upper1, &fc_empty);
	Assert(!fc_empty);

	multirange_get_bounds(fc_rangetyp, fc_mr, 0, &fc_lower2, &fc_upper2);

	return (range_cmp_bounds(fc_rangetyp, &fc_upper1, &fc_lower2) < 0);
}

bool multirange_before_multirange_internal(TypeCacheEntry *fc_rangetyp,
									  const MultirangeType *fc_mr1,
									  const MultirangeType *fc_mr2)
{
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;

	if (MultirangeIsEmpty(fc_mr1) || MultirangeIsEmpty(fc_mr2))
		return false;

	multirange_get_bounds(fc_rangetyp, fc_mr1, fc_mr1->rangeCount - 1,
						  &fc_lower1, &fc_upper1);
	multirange_get_bounds(fc_rangetyp, fc_mr2, 0,
						  &fc_lower2, &fc_upper2);

	return (range_cmp_bounds(fc_rangetyp, &fc_upper1, &fc_lower2) < 0);
}

/* 严格在右边吗? (内部版本) */
bool range_after_multirange_internal(TypeCacheEntry *fc_rangetyp,
								const RangeType *fc_r,
								const MultirangeType *fc_mr)
{
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;
	bool		fc_empty;
	int32		fc_range_count;

	if (RangeIsEmpty(fc_r) || MultirangeIsEmpty(fc_mr))
		return false;

	range_deserialize(fc_rangetyp, fc_r, &fc_lower1, &fc_upper1, &fc_empty);
	Assert(!fc_empty);

	fc_range_count = fc_mr->rangeCount;
	multirange_get_bounds(fc_rangetyp, fc_mr, fc_range_count - 1,
						  &fc_lower2, &fc_upper2);

	return (range_cmp_bounds(fc_rangetyp, &fc_lower1, &fc_upper2) > 0);
}

bool range_adjacent_multirange_internal(TypeCacheEntry *fc_rangetyp,
								   const RangeType *fc_r,
								   const MultirangeType *fc_mr)
{
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;
	bool		fc_empty;
	int32		fc_range_count;

	if (RangeIsEmpty(fc_r) || MultirangeIsEmpty(fc_mr))
		return false;

	range_deserialize(fc_rangetyp, fc_r, &fc_lower1, &fc_upper1, &fc_empty);
	Assert(!fc_empty);

	fc_range_count = fc_mr->rangeCount;
	multirange_get_bounds(fc_rangetyp, fc_mr, 0,
						  &fc_lower2, &fc_upper2);

	if (bounds_adjacent(fc_rangetyp, fc_upper1, fc_lower2))
		return true;

	if (fc_range_count > 1)
		multirange_get_bounds(fc_rangetyp, fc_mr, fc_range_count - 1,
							  &fc_lower2, &fc_upper2);

	if (bounds_adjacent(fc_rangetyp, fc_upper2, fc_lower1))
		return true;

	return false;
}

/* 相邻吗? */
Datum range_adjacent_multirange(PG_FUNCTION_ARGS)
{
	RangeType  *fc_r = PG_GETARG_RANGE_P(0);
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_adjacent_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

Datum multirange_adjacent_range(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	RangeType  *fc_r = PG_GETARG_RANGE_P(1);
	TypeCacheEntry *fc_typcache;

	if (RangeIsEmpty(fc_r) || MultirangeIsEmpty(fc_mr))
		return false;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));

	PG_RETURN_BOOL(range_adjacent_multirange_internal(fc_typcache->rngtype, fc_r, fc_mr));
}

Datum multirange_adjacent_multirange(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	TypeCacheEntry *fc_typcache;
	int32		fc_range_count1;
	int32		fc_range_count2;
	RangeBound	fc_lower1,
				fc_upper1,
				fc_lower2,
				fc_upper2;

	if (MultirangeIsEmpty(fc_mr1) || MultirangeIsEmpty(fc_mr2))
		return false;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	fc_range_count1 = fc_mr1->rangeCount;
	fc_range_count2 = fc_mr2->rangeCount;
	multirange_get_bounds(fc_typcache->rngtype, fc_mr1, fc_range_count1 - 1,
						  &fc_lower1, &fc_upper1);
	multirange_get_bounds(fc_typcache->rngtype, fc_mr2, 0,
						  &fc_lower2, &fc_upper2);
	if (bounds_adjacent(fc_typcache->rngtype, fc_upper1, fc_lower2))
		PG_RETURN_BOOL(true);

	if (fc_range_count1 > 1)
		multirange_get_bounds(fc_typcache->rngtype, fc_mr1, 0,
							  &fc_lower1, &fc_upper1);
	if (fc_range_count2 > 1)
		multirange_get_bounds(fc_typcache->rngtype, fc_mr2, fc_range_count2 - 1,
							  &fc_lower2, &fc_upper2);
	if (bounds_adjacent(fc_typcache->rngtype, fc_upper2, fc_lower1))
		PG_RETURN_BOOL(true);
	PG_RETURN_BOOL(false);
}

/* Btree 支持 */

/* btree 比较器 */
Datum multirange_cmp(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr1 = PG_GETARG_MULTIRANGE_P(0);
	MultirangeType *fc_mr2 = PG_GETARG_MULTIRANGE_P(1);
	int32		fc_range_count_1;
	int32		fc_range_count_2;
	int32		fc_range_count_max;
	int32		fc_i;
	TypeCacheEntry *fc_typcache;
	int			fc_cmp = 0;		/* 如果两个都是空的，我们将使用这个。 */

	/* 不同类型应该通过 ANYMULTIRANGE 匹配规则防止出现 */
	if (MultirangeTypeGetOid(fc_mr1) != MultirangeTypeGetOid(fc_mr2))
		elog(ERROR, "multirange types do not match");

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr1));

	fc_range_count_1 = fc_mr1->rangeCount;
	fc_range_count_2 = fc_mr2->rangeCount;

	/* 循环遍历源数据 */
	fc_range_count_max = Max(fc_range_count_1, fc_range_count_2);
	for (fc_i = 0; fc_i < fc_range_count_max; fc_i++)
	{
		RangeBound	fc_lower1,
					fc_upper1,
					fc_lower2,
					fc_upper2;

		/*
		 * 如果一个多范围更短，就好像它在末尾有空范围以扩展其长度。一个空范围比较早于任何其他范围，因此较短的多范围排在较长的前面。这与其他类型的行为相同，例如在字符串中 'aaa' < 'aaaaaa'。
		 */
		if (fc_i >= fc_range_count_1)
		{
			fc_cmp = -1;
			break;
		}
		if (fc_i >= fc_range_count_2)
		{
			fc_cmp = 1;
			break;
		}

		multirange_get_bounds(fc_typcache->rngtype, fc_mr1, fc_i, &fc_lower1, &fc_upper1);
		multirange_get_bounds(fc_typcache->rngtype, fc_mr2, fc_i, &fc_lower2, &fc_upper2);

		fc_cmp = range_cmp_bounds(fc_typcache->rngtype, &fc_lower1, &fc_lower2);
		if (fc_cmp == 0)
			fc_cmp = range_cmp_bounds(fc_typcache->rngtype, &fc_upper1, &fc_upper2);
		if (fc_cmp != 0)
			break;
	}

	PG_FREE_IF_COPY(fc_mr1, 0);
	PG_FREE_IF_COPY(fc_mr2, 1);

	PG_RETURN_INT32(fc_cmp);
}

/* 使用 multirange_cmp 函数的算术运算符 */
Datum multirange_lt(PG_FUNCTION_ARGS)
{
	int			fc_cmp = multirange_cmp(fcinfo);

	PG_RETURN_BOOL(fc_cmp < 0);
}

Datum multirange_le(PG_FUNCTION_ARGS)
{
	int			fc_cmp = multirange_cmp(fcinfo);

	PG_RETURN_BOOL(fc_cmp <= 0);
}

Datum multirange_ge(PG_FUNCTION_ARGS)
{
	int			fc_cmp = multirange_cmp(fcinfo);

	PG_RETURN_BOOL(fc_cmp >= 0);
}

Datum multirange_gt(PG_FUNCTION_ARGS)
{
	int			fc_cmp = multirange_cmp(fcinfo);

	PG_RETURN_BOOL(fc_cmp > 0);
}

/* multirange -> 范围函数 */

/* 找到包含多范围中所有内容的最小范围 */
Datum range_merge_from_multirange(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	Oid			fc_mltrngtypoid = MultirangeTypeGetOid(fc_mr);
	TypeCacheEntry *fc_typcache;
	RangeType  *fc_result;

	fc_typcache = multirange_get_typcache(fcinfo, fc_mltrngtypoid);

	if (MultirangeIsEmpty(fc_mr))
	{
		fc_result = make_empty_range(fc_typcache->rngtype);
	}
	else if (fc_mr->rangeCount == 1)
	{
		fc_result = multirange_get_range(fc_typcache->rngtype, fc_mr, 0);
	}
	else
	{
		RangeBound	fc_firstLower,
					fc_firstUpper,
					fc_lastLower,
					fc_lastUpper;

		multirange_get_bounds(fc_typcache->rngtype, fc_mr, 0,
							  &fc_firstLower, &fc_firstUpper);
		multirange_get_bounds(fc_typcache->rngtype, fc_mr, fc_mr->rangeCount - 1,
							  &fc_lastLower, &fc_lastUpper);

		fc_result = make_range(fc_typcache->rngtype, &fc_firstLower, &fc_lastUpper, false);
	}

	PG_RETURN_RANGE_P(fc_result);
}

/* 将多范围转换为一组范围 */
Datum multirange_unnest(PG_FUNCTION_ARGS)
{
	typedef struct
	{
		MultirangeType *mr;
		TypeCacheEntry *typcache;
		int			index;
	} multirange_unnest_fctx;

	FuncCallContext *fc_funcctx;
	multirange_unnest_fctx *fc_fctx;
	MemoryContext fc_oldcontext;

	/* 仅在函数的第一次调用时完成的工作 */
	if (SRF_IS_FIRSTCALL())
	{
		MultirangeType *fc_mr;

		/* 为跨调用持久性创建一个函数上下文 */
		fc_funcctx = SRF_FIRSTCALL_INIT();

		/*
		 * 切换到适合多次函数调用的内存上下文
		 */
		fc_oldcontext = MemoryContextSwitchTo(fc_funcctx->multi_call_memory_ctx);

		/*
		 * 获取多范围值并根据需要解冻。我们不能早些这样做，因为如果必须解冻，我们希望解冻的副本在 multi_call_memory_ctx 中，这样它将在完成时消失，而不是之前。(如果没有解冻发生，我们假设原始传递的多范围将在那时保留。)
		 */
		fc_mr = PG_GETARG_MULTIRANGE_P(0);

		/* 为用户上下文分配内存 */
		fc_fctx = (multirange_unnest_fctx *) palloc(sizeof(multirange_unnest_fctx));

		/* 初始化状态 */
		fc_fctx->mr = fc_mr;
		fc_fctx->index = 0;
		fc_fctx->typcache = lookup_type_cache(MultirangeTypeGetOid(fc_mr),
										   TYPECACHE_MULTIRANGE_INFO);

		fc_funcctx->user_fctx = fc_fctx;
		MemoryContextSwitchTo(fc_oldcontext);
	}

	/* 每次调用函数时完成的工作 */
	fc_funcctx = SRF_PERCALL_SETUP();
	fc_fctx = fc_funcctx->user_fctx;

	if (fc_fctx->index < fc_fctx->mr->rangeCount)
	{
		RangeType  *fc_range;

		fc_range = multirange_get_range(fc_fctx->typcache->rngtype,
									 fc_fctx->mr,
									 fc_fctx->index);
		fc_fctx->index++;

		SRF_RETURN_NEXT(fc_funcctx, RangeTypePGetDatum(fc_range));
	}
	else
	{
		/* 当没有更多内容时执行 */
		SRF_RETURN_DONE(fc_funcctx);
	}
}

/* 哈希支持 */

/* 哈希一个多范围值 */
Datum hash_multirange(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	uint32		fc_result = 1;
	TypeCacheEntry *fc_typcache,
			   *fc_scache;
	int32		fc_range_count,
				fc_i;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));
	fc_scache = fc_typcache->rngtype->rngelemtype;
	if (!OidIsValid(fc_scache->hash_proc_finfo.fn_oid))
	{
		fc_scache = lookup_type_cache(fc_scache->type_id,
								   TYPECACHE_HASH_PROC_FINFO);
		if (!OidIsValid(fc_scache->hash_proc_finfo.fn_oid))
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_FUNCTION),
					 errmsg("could not identify a hash function for type %s",
							format_type_be(fc_scache->type_id))));
	}

	fc_range_count = fc_mr->rangeCount;
	for (fc_i = 0; fc_i < fc_range_count; fc_i++)
	{
		RangeBound	fc_lower,
					fc_upper;
		uint8		fc_flags = MultirangeGetFlagsPtr(fc_mr)[fc_i];
		uint32		fc_lower_hash;
		uint32		fc_upper_hash;
		uint32		fc_range_hash;

		multirange_get_bounds(fc_typcache->rngtype, fc_mr, fc_i, &fc_lower, &fc_upper);

		if (RANGE_HAS_LBOUND(fc_flags))
			fc_lower_hash = DatumGetUInt32(FunctionCall1Coll(&fc_scache->hash_proc_finfo,
														  fc_typcache->rngtype->rng_collation,
														  fc_lower.val));
		else
			fc_lower_hash = 0;

		if (RANGE_HAS_UBOUND(fc_flags))
			fc_upper_hash = DatumGetUInt32(FunctionCall1Coll(&fc_scache->hash_proc_finfo,
														  fc_typcache->rngtype->rng_collation,
														  fc_upper.val));
		else
			fc_upper_hash = 0;

		/* 合并标志和边界的哈希 */
		fc_range_hash = hash_uint32((uint32) fc_flags);
		fc_range_hash ^= fc_lower_hash;
		fc_range_hash = pg_rotate_left32(fc_range_hash, 1);
		fc_range_hash ^= fc_upper_hash;

		/*
		 * 使用与 hash_array 相同的方法来组合各个元素的哈希值：
		 */
		fc_result = (fc_result << 5) - fc_result + fc_range_hash;
	}

	PG_FREE_IF_COPY(fc_mr, 0);

	PG_RETURN_UINT32(fc_result);
}

/*
 * 通过将一个值哈希到64位值并使用种子，返回64位值。否则，与 hash_multirange 相似。
 */
Datum hash_multirange_extended(PG_FUNCTION_ARGS)
{
	MultirangeType *fc_mr = PG_GETARG_MULTIRANGE_P(0);
	Datum		fc_seed = PG_GETARG_DATUM(1);
	uint64		fc_result = 1;
	TypeCacheEntry *fc_typcache,
			   *fc_scache;
	int32		fc_range_count,
				fc_i;

	fc_typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(fc_mr));
	fc_scache = fc_typcache->rngtype->rngelemtype;
	if (!OidIsValid(fc_scache->hash_extended_proc_finfo.fn_oid))
	{
		fc_scache = lookup_type_cache(fc_scache->type_id,
								   TYPECACHE_HASH_EXTENDED_PROC_FINFO);
		if (!OidIsValid(fc_scache->hash_extended_proc_finfo.fn_oid))
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_FUNCTION),
					 errmsg("could not identify a hash function for type %s",
							format_type_be(fc_scache->type_id))));
	}

	fc_range_count = fc_mr->rangeCount;
	for (fc_i = 0; fc_i < fc_range_count; fc_i++)
	{
		RangeBound	fc_lower,
					fc_upper;
		uint8		fc_flags = MultirangeGetFlagsPtr(fc_mr)[fc_i];
		uint64		fc_lower_hash;
		uint64		fc_upper_hash;
		uint64		fc_range_hash;

		multirange_get_bounds(fc_typcache->rngtype, fc_mr, fc_i, &fc_lower, &fc_upper);

		if (RANGE_HAS_LBOUND(fc_flags))
			fc_lower_hash = DatumGetUInt64(FunctionCall2Coll(&fc_scache->hash_extended_proc_finfo,
														  fc_typcache->rngtype->rng_collation,
														  fc_lower.val,
														  fc_seed));
		else
			fc_lower_hash = 0;

		if (RANGE_HAS_UBOUND(fc_flags))
			fc_upper_hash = DatumGetUInt64(FunctionCall2Coll(&fc_scache->hash_extended_proc_finfo,
														  fc_typcache->rngtype->rng_collation,
														  fc_upper.val,
														  fc_seed));
		else
			fc_upper_hash = 0;

		/* 合并标志和边界的哈希 */
		fc_range_hash = DatumGetUInt64(hash_uint32_extended((uint32) fc_flags,
														 DatumGetInt64(fc_seed)));
		fc_range_hash ^= fc_lower_hash;
		fc_range_hash = ROTATE_HIGH_AND_LOW_32BITS(fc_range_hash);
		fc_range_hash ^= fc_upper_hash;

		/*
		 * 使用与 hash_array 相同的方法来组合各个元素的哈希值：
		 */
		fc_result = (fc_result << 5) - fc_result + fc_range_hash;
	}

	PG_FREE_IF_COPY(fc_mr, 0);

	PG_RETURN_UINT64(fc_result);
}
